import { ErrorInfo, SDKConfig } from '../types';
import { 
  getCurrentUrl, 
  getUserAgent, 
  formatErrorStack,
  shouldSample 
} from '../utils';

export class ErrorMonitor {
  private config: SDKConfig;
  private errorHandler: (error: ErrorInfo) => void;

  constructor(config: SDKConfig, errorHandler: (error: ErrorInfo) => void) {
    this.config = config;
    this.errorHandler = errorHandler;
  }

  // 初始化错误监控
  public init(): void {
    // 监听JavaScript错误
    this.setupJsErrorHandler();
    
    // 监听Promise错误
    this.setupPromiseErrorHandler();
    
    // 监听资源加载错误
    this.setupResourceErrorHandler();
    
    // 监听HTTP请求错误
    this.setupHttpErrorHandler();
    
    // 监听控制台错误
    if (this.config.enableConsole) {
      this.setupConsoleErrorHandler();
    }
  }

  // 设置JavaScript错误处理器
  private setupJsErrorHandler(): void {
    window.addEventListener('error', (event) => {
      if (!shouldSample(this.config.sampleRate)) {
        return;
      }

      const errorInfo: ErrorInfo = {
        type: 'js',
        message: event.message || 'Unknown JavaScript error',
        stack: event.error?.stack || '',
        filename: event.filename || '',
        lineno: event.lineno || 0,
        colno: event.colno || 0,
        timestamp: Date.now(),
        url: getCurrentUrl(),
        userAgent: getUserAgent(),
        extra: {
          error: event.error
        }
      };

      this.errorHandler(errorInfo);
    }, true);
  }

  // 设置Promise错误处理器
  private setupPromiseErrorHandler(): void {
    window.addEventListener('unhandledrejection', (event) => {
      if (!shouldSample(this.config.sampleRate)) {
        return;
      }

      const errorInfo: ErrorInfo = {
        type: 'promise',
        message: event.reason?.message || event.reason || 'Unhandled Promise rejection',
        stack: event.reason?.stack || '',
        timestamp: Date.now(),
        url: getCurrentUrl(),
        userAgent: getUserAgent(),
        extra: {
          reason: event.reason
        }
      };

      this.errorHandler(errorInfo);
    });
  }

  // 设置资源加载错误处理器
  private setupResourceErrorHandler(): void {
    window.addEventListener('error', (event) => {
      if (!shouldSample(this.config.sampleRate)) {
        return;
      }

      // 只处理资源加载错误
      if (event.target && event.target !== window) {
        const target = event.target as HTMLElement;
        const errorInfo: ErrorInfo = {
          type: 'resource',
          message: `Failed to load resource: ${target.tagName}`,
          timestamp: Date.now(),
          url: getCurrentUrl(),
          userAgent: getUserAgent(),
          extra: {
            tagName: target.tagName,
            src: (target as HTMLImageElement).src || (target as HTMLScriptElement).src || (target as HTMLLinkElement).href,
            target: target
          }
        };

        this.errorHandler(errorInfo);
      }
    }, true);
  }

  // 设置HTTP请求错误处理器
  private setupHttpErrorHandler(): void {
    // 拦截XMLHttpRequest
    const originalXHROpen = XMLHttpRequest.prototype.open;
    const originalXHRSend = XMLHttpRequest.prototype.send;

    XMLHttpRequest.prototype.open = function(method: string, url: string, async?: boolean, username?: string | null, password?: string | null) {
      (this as any)._xhrMethod = method;
      (this as any)._xhrUrl = url;
      return originalXHROpen.call(this, method, url, async, username, password);
    };

    XMLHttpRequest.prototype.send = function(body?: Document | XMLHttpRequestBodyInit | null) {
      this.addEventListener('error', (event) => {
        if (!shouldSample(this.config.sampleRate)) {
          return;
        }

        const errorInfo: ErrorInfo = {
          type: 'http',
          message: `XHR Error: ${(this as any)._xhrMethod} ${(this as any)._xhrUrl}`,
          timestamp: Date.now(),
          url: getCurrentUrl(),
          userAgent: getUserAgent(),
          extra: {
            method: (this as any)._xhrMethod,
            url: (this as any)._xhrUrl,
            status: this.status,
            statusText: this.statusText
          }
        };

        this.errorHandler(errorInfo);
      });

      return originalXHRSend.call(this, body);
    };

    // 拦截Fetch API
    const originalFetch = window.fetch;
    window.fetch = async (input: RequestInfo | URL, init?: RequestInit) => {
      try {
        const response = await originalFetch(input, init);
        
        if (!response.ok && shouldSample(this.config.sampleRate)) {
          const errorInfo: ErrorInfo = {
            type: 'http',
            message: `Fetch Error: ${response.status} ${response.statusText}`,
            timestamp: Date.now(),
            url: getCurrentUrl(),
            userAgent: getUserAgent(),
            extra: {
              method: init?.method || 'GET',
              url: typeof input === 'string' ? input : input.toString(),
              status: response.status,
              statusText: response.statusText
            }
          };

          this.errorHandler(errorInfo);
        }
        
        return response;
      } catch (error) {
        if (shouldSample(this.config.sampleRate)) {
          const errorInfo: ErrorInfo = {
            type: 'http',
            message: `Fetch Network Error: ${error}`,
            timestamp: Date.now(),
            url: getCurrentUrl(),
            userAgent: getUserAgent(),
            extra: {
              method: init?.method || 'GET',
              url: typeof input === 'string' ? input : input.toString(),
              error: error
            }
          };

          this.errorHandler(errorInfo);
        }
        throw error;
      }
    };
  }

  // 设置控制台错误处理器
  private setupConsoleErrorHandler(): void {
    const originalConsoleError = console.error;
    const originalConsoleWarn = console.warn;

    console.error = (...args: any[]) => {
      if (shouldSample(this.config.sampleRate)) {
        const errorInfo: ErrorInfo = {
          type: 'custom',
          message: `Console Error: ${args.map(arg => String(arg)).join(' ')}`,
          timestamp: Date.now(),
          url: getCurrentUrl(),
          userAgent: getUserAgent(),
          extra: {
            consoleArgs: args
          }
        };

        this.errorHandler(errorInfo);
      }

      originalConsoleError.apply(console, args);
    };

    console.warn = (...args: any[]) => {
      if (shouldSample(this.config.sampleRate)) {
        const errorInfo: ErrorInfo = {
          type: 'custom',
          message: `Console Warning: ${args.map(arg => String(arg)).join(' ')}`,
          timestamp: Date.now(),
          url: getCurrentUrl(),
          userAgent: getUserAgent(),
          extra: {
            consoleArgs: args
          }
        };

        this.errorHandler(errorInfo);
      }

      originalConsoleWarn.apply(console, args);
    };
  }

  // 手动上报错误
  public reportError(error: Error | string, extra?: Record<string, any>): void {
    if (!shouldSample(this.config.sampleRate)) {
      return;
    }

    const errorInfo: ErrorInfo = {
      type: 'custom',
      message: typeof error === 'string' ? error : error.message,
      stack: typeof error === 'string' ? '' : formatErrorStack(error),
      timestamp: Date.now(),
      url: getCurrentUrl(),
      userAgent: getUserAgent(),
      extra: extra
    };

    this.errorHandler(errorInfo);
  }

  // 销毁错误监控器
  public destroy(): void {
    // 移除事件监听器
    window.removeEventListener('error', this.setupJsErrorHandler);
    window.removeEventListener('unhandledrejection', this.setupPromiseErrorHandler);
    
    // 恢复原始方法
    if (this.config.enableConsole) {
      console.error = console.error;
      console.warn = console.warn;
    }
  }
} 